// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_TILES_TILE_PRIORITY_H_
#define CC_TILES_TILE_PRIORITY_H_

#include <stddef.h>

#include <algorithm>
#include <limits>
#include <memory>
#include <string>

#include "base/trace_event/trace_event_argument.h"
#include "cc/base/cc_export.h"

namespace base {
class Value;
}

namespace cc {

enum WhichTree {
    // Note: these must be 0 and 1 because we index with them in various places,
    // e.g. in Tile::priority_.
    ACTIVE_TREE = 0,
    PENDING_TREE = 1,
    LAST_TREE = 1
    // Be sure to update WhichTreeAsValue when adding new fields.
};
std::unique_ptr<base::Value> WhichTreeAsValue(WhichTree tree);

enum TileResolution {
    LOW_RESOLUTION = 0,
    HIGH_RESOLUTION = 1,
    NON_IDEAL_RESOLUTION = 2,
};
std::string TileResolutionToString(TileResolution resolution);

struct CC_EXPORT TilePriority {
    enum PriorityBin { NOW,
        SOON,
        EVENTUALLY };

    TilePriority()
        : resolution(NON_IDEAL_RESOLUTION)
        , priority_bin(EVENTUALLY)
        , distance_to_visible(std::numeric_limits<float>::infinity())
    {
    }

    TilePriority(TileResolution resolution,
        PriorityBin bin,
        float distance_to_visible)
        : resolution(resolution)
        , priority_bin(bin)
        , distance_to_visible(distance_to_visible)
    {
    }

    void AsValueInto(base::trace_event::TracedValue* dict) const;

    bool IsHigherPriorityThan(const TilePriority& other) const
    {
        return priority_bin < other.priority_bin || (priority_bin == other.priority_bin && distance_to_visible < other.distance_to_visible);
    }

    TileResolution resolution;
    PriorityBin priority_bin;
    float distance_to_visible;
};

std::string TilePriorityBinToString(TilePriority::PriorityBin bin);

enum TileMemoryLimitPolicy {
    // Nothing. This mode is used when visible is set to false.
    ALLOW_NOTHING = 0,

    // You might be made visible, but you're not being interacted with.
    ALLOW_ABSOLUTE_MINIMUM = 1, // Tall.

    // You're being interacted with, but we're low on memory.
    ALLOW_PREPAINT_ONLY = 2, // Grande.

    // You're the only thing in town. Go crazy.
    ALLOW_ANYTHING = 3 // Venti.
};
std::string TileMemoryLimitPolicyToString(TileMemoryLimitPolicy policy);

enum TreePriority {
    SAME_PRIORITY_FOR_BOTH_TREES,
    SMOOTHNESS_TAKES_PRIORITY,
    NEW_CONTENT_TAKES_PRIORITY,
    LAST_TREE_PRIORITY = NEW_CONTENT_TAKES_PRIORITY
    // Be sure to update TreePriorityAsValue when adding new fields.
};
std::string TreePriorityToString(TreePriority prio);

class GlobalStateThatImpactsTilePriority {
public:
    GlobalStateThatImpactsTilePriority()
        : memory_limit_policy(ALLOW_NOTHING)
        , soft_memory_limit_in_bytes(0)
        , hard_memory_limit_in_bytes(0)
        , num_resources_limit(0)
        , tree_priority(SAME_PRIORITY_FOR_BOTH_TREES)
    {
    }

    TileMemoryLimitPolicy memory_limit_policy;

    size_t soft_memory_limit_in_bytes;
    size_t hard_memory_limit_in_bytes;
    size_t num_resources_limit;

    TreePriority tree_priority;

    bool operator==(const GlobalStateThatImpactsTilePriority& other) const
    {
        return memory_limit_policy == other.memory_limit_policy && soft_memory_limit_in_bytes == other.soft_memory_limit_in_bytes && hard_memory_limit_in_bytes == other.hard_memory_limit_in_bytes && num_resources_limit == other.num_resources_limit && tree_priority == other.tree_priority;
    }
    bool operator!=(const GlobalStateThatImpactsTilePriority& other) const
    {
        return !(*this == other);
    }

    void AsValueInto(base::trace_event::TracedValue* dict) const;
};

} // namespace cc

#endif // CC_TILES_TILE_PRIORITY_H_
